package org.papervision3d.cameras
{
    import org.papervision3d.Papervision3D;
    import org.papervision3d.core.Number3D;
    import org.papervision3d.core.Matrix3D;
    import org.papervision3d.core.proto.CameraObject3D;
    import org.papervision3d.objects.DisplayObject3D;
    import org.papervision3d.objects.DisplayObject3D;

    // The Camera3D class creates a camera that views the area around a target object.
    // A camera defines the view from which a scene will be rendered. Different camera settings would present a scene from different points of view.
    // 3D cameras simulate still-image, motion picture, or video cameras of the real world. When rendering, the scene is drawn as if you were looking through the camera lens.
    public class Camera3D extends CameraObject3D
    {
        // A DisplayObject3D object that specifies the current position the camera is looking at.
        public var target:DisplayObject3D;

        // A Number3D object that specifies the desired position of the camera in 3D space. Only used when calling update().
        public var goto:Number3D;
    
        // The Camera3D constructor creates cameras that view the area around a target object.
        // Its initial position can be specified in the initObject.
        // @param zoom        This value specifies the scale at which the 3D objects are rendered. Higher values magnify the scene, compressing distance. Use it in conjunction with focus.
        // @param focus       This value is a positive number representing the distance of the observer from the front clipping plane, which is the closest any object can be to the camera. Use it in conjunction with zoom.
        // @param initObject  An optional object that contains user defined properties with which to populate the newly created DisplayObject3D.
        // It includes x, y, z, rotationX, rotationY, rotationZ, scaleX, scaleY scaleZ and a user defined extra object.
        // If extra is not an object, it is ignored. All properties of the extra field are copied into the new instance. The properties specified with extra are publicly available.
        // The following initObject property is also recognized by the constructor:
        // sort: A Boolean value that determines whether the 3D objects are z-depth sorted between themselves when rendering. The default value is true.
        public function Camera3D(target:DisplayObject3D = null, zoom:Number = 2, focus:Number = 100, initObject:Object = null)
        {
            super(zoom, focus, initObject);
    
            this.target = target || DisplayObject3D.ZERO;
    
            this.goto = new Number3D(this.x, this.y, this.z);
        }

        // [internal-use] Transforms world coordinates into camera space.
        public override function transformView():void
        {
            this.lookAt(this.target);
    
            super.transformView();
        }
    
        // [experimental] Hovers the camera around as the user moves the mouse, without changing the distance to the target. This greatly enhances the 3D illusion.
        // @param type    Type of movement.
        // @param mouseX  Indicates the x coordinate of the mouse position in relation to the canvas MovieClip.
        // @param mouseY  Indicates the y coordinate of the mouse position in relation to the canvas MovieClip.
        public function hover(type:Number, mouseX:Number, mouseY:Number, camSpeed:Number = 8):Boolean
        {
            var target:DisplayObject3D = this.target;
            var goto:Number3D = this.goto;
    
            switch(type)
            {
                case 0:
                    // Sphere mapped camera (free)
                    var dX:Number = goto.x - target.x;
                    var dZ:Number = goto.z - target.z;
    
                    var ang:Number    = Math.atan2(dZ, dX);
                    var dist:Number   = Math.sqrt(dX*dX + dZ*dZ);
                    var xMouse:Number = 0.5 * mouseX;
    
                    var camX:Number = dist * Math.cos(ang - xMouse);
                    var camZ:Number = dist * Math.sin(ang - xMouse);
                    var camY:Number = goto.y - 300 * mouseY;
    
                    var delX:Number = this.x - camX;
                    var delY:Number = this.y - camY;
                    var delZ:Number = this.z - camZ;

                    if (Math.sqrt(delX*delX + delY*delY + delZ*delZ) < 10)
                        return false;

                    this.x -= (this.x - camX) / camSpeed;
                    this.y -= (this.y - camY) / camSpeed;
                    this.z -= (this.z - camZ) / camSpeed;
                    break;
    
                case 1:
                    this.x -= (this.x - 1000 * mouseX) / camSpeed;
                    this.y -= (this.y - 1000 * mouseY) / camSpeed;
    //              this.z -= (this.z - ) /camSpeed;
                    break;
    
            }
            return true;
        }
    }
}   
